package edu.northwestern.cbits.purple_robot_manager.models;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.json.JSONArray;
import org.json.JSONException;
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.net.Uri;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.PreferenceCategory;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.support.v4.content.LocalBroadcastManager;
import edu.northwestern.cbits.purple_robot_manager.R;
import edu.northwestern.cbits.purple_robot_manager.activities.settings.SettingsKeys;
import edu.northwestern.cbits.purple_robot_manager.logging.LogManager;
import edu.northwestern.cbits.purple_robot_manager.probes.Probe;
import edu.northwestern.cbits.purple_robot_manager.util.Slugify;
public class ModelManager extends BroadcastReceiver
{
private static final String PERSISTED_MODELS = "model_manager_peristed_models";
private static ModelManager _instance = null;
private Context _context = null;
private List<Model> _models = new ArrayList<>();
private final HashMap<String, Object> _milieu = new HashMap<>();
private final HashMap<String, String> _keyCache = new HashMap<>();
private HashSet<String> _modelUrls = new HashSet<>();
private ModelManager(Context context)
{
if (ModelManager._instance != null)
throw new IllegalStateException("Already instantiated");
this._context = context.getApplicationContext();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Probe.PROBE_READING);
LocalBroadcastManager localManager = LocalBroadcastManager.getInstance(context);
localManager.registerReceiver(this, intentFilter);
this.loadPersistedModels();
}
public static ModelManager getInstance(Context context)
{
if (ModelManager._instance == null)
{
ModelManager._instance = new ModelManager(context.getApplicationContext());
}
return ModelManager._instance;
}
@SuppressWarnings("deprecation")
public PreferenceScreen buildPreferenceScreen(Context context, PreferenceManager manager)
{
PreferenceScreen screen = manager.createPreferenceScreen(context);
screen.setOrder(0);
screen.setTitle(R.string.title_preference_models_screen);
screen.setKey(SettingsKeys.MODELS_SCREEN_KEY);
PreferenceCategory globalCategory = new PreferenceCategory(context);
globalCategory.setTitle(R.string.title_preference_models_global_category);
globalCategory.setKey("key_available_models");
screen.addPreference(globalCategory);
CheckBoxPreference enabled = new CheckBoxPreference(context);
enabled.setTitle(R.string.title_preference_models_enable_models);
enabled.setKey("config_models_enabled");
enabled.setDefaultValue(Model.DEFAULT_ENABLED);
globalCategory.addPreference(enabled);
PreferenceCategory probesCategory = new PreferenceCategory(context);
probesCategory.setTitle(R.string.title_preference_models_available_category);
probesCategory.setKey("key_available_models");
screen.addPreference(probesCategory);
for (Model model : this.allModels(context))
{
PreferenceScreen modelScreen = model.preferenceScreen(context, manager);
if (modelScreen != null)
screen.addPreference(modelScreen);
}
return screen;
}
private List<Model> allModels(Context context)
{
ArrayList<Model> models = new ArrayList<>();
models.addAll(this._models);
return models;
}
@SuppressLint("DefaultLocale")
public void onReceive(Context context, Intent intent)
{
Bundle extras = intent.getExtras();
if (extras.containsKey("FROM_MODEL") || extras.getString("PROBE") == null)
return;
String[] nameComponents = extras.getString("PROBE").split("\\.");
String probeName = nameComponents[nameComponents.length - 1];
for (String key : extras.keySet())
{
if ("PROBE".equals(key) || "GUID".equals(key) || "TIMESTAMP".equals(key))
{
// Do nothing...
}
else
{
String probeKey = probeName + " " + key;
String slug = this._keyCache.get(probeKey);
if (slug == null)
{
slug = probeKey.toLowerCase(Locale.getDefault()).replaceAll("_", " ");
slug = Slugify.slugify(slug).replaceAll("-", "_");
this._keyCache.put(probeKey, slug);
}
this._milieu.put(slug, extras.get(key));
}
}
for (Model model : this.allModels(context))
{
HashMap<String, Object> snapshot = new HashMap<>();
synchronized (this._milieu)
{
snapshot.putAll(this._milieu);
}
if (model != null)
model.predict(context, snapshot);
}
}
public Model fetchModelByName(Context context, String name)
{
for (Model model : this._models)
{
if (name.equals(model.name(context)))
return model;
}
return null;
}
public void addModel(String jsonUrl)
{
this.deleteModel(jsonUrl);
this._modelUrls.add(jsonUrl);
Model m = Model.modelForUrl(this._context, jsonUrl);
if (m != null)
this._models.add(m);
this.persistModels();
}
private void persistModels()
{
JSONArray urls = new JSONArray();
for (String url : this._modelUrls)
{
urls.put(url);
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this._context);
Editor e = prefs.edit();
e.putString(ModelManager.PERSISTED_MODELS, urls.toString());
e.commit();
}
private void loadPersistedModels()
{
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this._context);
try
{
JSONArray urls = new JSONArray(prefs.getString(ModelManager.PERSISTED_MODELS, "[]"));
for (int i = 0; i < urls.length(); i++)
{
String url = urls.getString(i);
this.addModel(url);
}
}
catch (JSONException e)
{
LogManager.getInstance(this._context).logException(e);
}
}
public void deleteModel(String jsonUrl)
{
synchronized (this._models)
{
List<Model> toRemove = new ArrayList<>();
for (Model model : this._models)
{
Uri uri = model.uri();
if (uri != null && uri.toString().equals(jsonUrl))
toRemove.add(model);
}
this._models.removeAll(toRemove);
}
this._modelUrls.remove(jsonUrl);
this.persistModels();
}
public void enableModel(String jsonUrl)
{
for (Model model : this._models)
{
Uri uri = model.uri();
if (uri != null && uri.toString().equals(jsonUrl))
model.enable(this._context);
}
}
public void disableModel(String jsonUrl)
{
for (Model model : this._models)
{
Uri uri = model.uri();
if (uri != null && uri.toString().equals(jsonUrl))
model.disable(this._context);
}
}
public boolean enabled(Context context)
{
SharedPreferences prefs = Probe.getPreferences(context);
return prefs.getBoolean("config_models_enabled", Model.DEFAULT_ENABLED);
}
public Map<String, Object> models(Context context)
{
HashMap<String, Object> modelMap = new HashMap<>();
for (Model m : this._models)
{
modelMap.put(m.title(context), "" + m.uri());
}
return modelMap;
}
public Map<String, Object> readings(Context context)
{
return this._milieu;
}
public Model fetchModelByTitle(Context context, String title)
{
if (title == null)
return null;
for (Model m : this._models)
{
if (title.equals(m.title(context)))
return m;
}
return null;
}
public Map<String, Object> predictions(Context context)
{
HashMap<String, Object> predictions = new HashMap<>();
for (Model m : this._models)
{
predictions.put(m.title(context), m.latestPrediction(context));
}
return predictions;
}
}